package main

import (
	"context"
	"crypto/x509"
	"fmt"
	"io"
	"log"
	"os"
	"protobuf-learn/proto"
	"time"

	"golang.org/x/sync/errgroup"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
)

func main() {
	// load tls from public CA
	//tlsCredentials := credentials.NewTLS(&tls.Config{})

	// load tls from privite CA
	certPool := x509.NewCertPool()
	cert, err := os.ReadFile("certs/ca.crt")
	if err != nil {
		log.Fatal(err)
	}
	if ok := certPool.AppendCertsFromPEM(cert); !ok {
		log.Fatal("failed to append CA cert")
	}
	tlsCredentials := credentials.NewClientTLSFromCert(certPool, "")

	address := ":50051"
	ctx := context.Background()
	// initialise our grpc connection
	conn, err := grpc.NewClient(
		address,
		//grpc.WithTransportCredentials(insecure.NewCredentials()),
		grpc.WithTransportCredentials(tlsCredentials),
	)
	if err != nil {
		log.Fatal(err)
	}
	// create a client
	client := proto.NewStreamingServiceClient(conn)
	// initialise our stream
	stream, err := client.Echo(ctx)
	if err != nil {
		log.Fatal(err)
	}
	eg, ctx := errgroup.WithContext(ctx)

	// create a separate go routine to listen to the server response
	eg.Go(func() error {
		// loop for each message from server
		for {
			res, err := stream.Recv()
			if err != nil {
				// check if stream is close
				if err == io.EOF {
					break
				}
				return err
			}
			// log the message
			log.Printf("message received from server: %s", res.GetMessage())
		}

		return nil
	})

	for i := range 5 {
		req := &proto.EchoRequest{
			Message: fmt.Sprintf("hello %d", i),
		}
		// send some message from the client
		err := stream.Send(req)
		if err != nil {
			log.Fatal(err)
		}

		time.Sleep(time.Second * 2)
	}

	// close the client stream
	if err := stream.CloseSend(); err != nil {
		log.Fatal(err)
	}

	// wait for the server go routine to finish
	if err := eg.Wait(); err != nil {
		log.Fatal(err)
	}

	fmt.Println("finish")
}
